﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace TestBed
{
    public partial class Form1 : Form
    {
        Random rand = new Random();
        private DataTable dtNormal;

        enum eColumnName
        {
            GameNum = 0,
            Competence0,
            Competence1,
            Competence2,
            eps0,
            eps1,
            eps2,
            avgUtilityOfTheGame,
            Player0NumOfTurnsPlayed,
            Player1NumOfTurnsPlayed,
            Player2NumOfTurnsPlayed
            //More column names can be added (remember to maintain the correct order as in the file!!!)
        }

        public Form1()
        {
            InitializeComponent();
        }

        private void ReadCSV_Click(object sender, EventArgs e)
        {
            string errors;
            string filePath = tbFilePath.Text;
            DataTable dt;

            if (!StartReading(filePath, out dt, out errors)){
                int xxx = 666;
            }
        }

        private void btnReadfilesInFolder_Click(object sender, EventArgs e)
        {
            string dirPath = tbDirectoryPath.Text;
            //Check if input dir was emtpy and insert default dir
            if (string.IsNullOrEmpty(tbDirectoryPath.Text)) {
                dirPath = @"C:\temp2\";
            }
            string errors;
            DataTable dt;
            List<DataTable> dtArray = new List<DataTable>();
            DirectoryInfo dir = new DirectoryInfo(dirPath);
            FileInfo[] csvFiles = dir.GetFiles("*.csv");

            foreach (FileInfo fi in csvFiles){
                string filePath = dirPath + "\\" + fi.Name;
                if (StartReading(filePath, out dt, out errors))
                {
                    dtArray.Add(dt);
                }
            }

            //go over the data tables list:
            foreach (DataTable dtInList in dtArray)
            {                
                //example to parse the data into numbers
                string temp = dtInList.Rows[2].ItemArray[3].ToString();
                double tempInt;
                if (!double.TryParse(temp,out tempInt)){
                    errors = "error parsing...";
                }
            }
        }

        private bool StartReading(string inFilePath, out DataTable outDt, out string outErrors) 
        {
            bool retVal = false;
            outErrors = string.Empty;
            int gameNumber = 0;

            if (string.IsNullOrEmpty(inFilePath)) {
                inFilePath = @"C:\temp1\data.csv";
            }

            DataTable dt = new DataTable();
            outDt = BuildDataTable(inFilePath, out gameNumber, out outErrors);

            retVal = (outDt != null);
           
            return retVal;
        }

        /// <summary>
        /// Insert an experiment with one line per problem and it creates a new file with X lines of each problem.
        /// </summary>
        /// <param name="inFilePath"></param>
        /// <param name="outErrors"></param>
        /// <returns></returns>
        private bool CreateExperiment(string inFilePath, out string outErrors)
        {
            bool retVal = false;
            outErrors = string.Empty;
            int gameNumber = 0;
            int NUMBEROFLINESTOCREATE = 50;

            if (string.IsNullOrEmpty(inFilePath))
            {
                inFilePath = @"C:\exp\data.csv";
            }

            DataTable dt = BuildDataTable(inFilePath, out gameNumber, out outErrors);
            if (dt != null)
            {
                dt.Rows.RemoveAt(0);
                DataTable newDT = new DataTable();
                foreach (DataRow row in dt.Rows)
                {
                    for (int i = 0; i < NUMBEROFLINESTOCREATE; i++)
                    {
                        newDT.Rows.Add(row);
                    }
                }
                retVal = true;
            }

            return retVal;
        }

        /// <summary>
        /// Create a new experiment data input
        /// </summary>
        /// <param name="inFilePath"></param>
        /// <param name="outErrors"></param>
        /// <returns></returns>
        private bool ExperimentGenerator(out string outErrors)
        {
            bool retVal = false;
            outErrors = string.Empty;
            int numberOfGamesPerExperiment = 20;
            int numberOfExperimentsToCreate = 500;

            //Set the competence level, the higher it is - the better the player is.
            double competence0;
            double competence1;
            double competence2;
            double eps0;
            double eps1;
            double eps2;
            int roundsPerGame;

            DataRow row1; //a row

            DataTable dtNormal = new DataTable("data");
            dtNormal.Columns.Add(new DataColumn("Game_Number", typeof(int)));
            dtNormal.Columns.Add(new DataColumn("Rounds", typeof(double)));
            dtNormal.Columns.Add(new DataColumn("Competence2", typeof(double)));   
            dtNormal.Columns.Add(new DataColumn("Competence1", typeof(double)));
            dtNormal.Columns.Add(new DataColumn("Competence0", typeof(double)));
            dtNormal.Columns.Add(new DataColumn("Epsilon2", typeof(double)));
            dtNormal.Columns.Add(new DataColumn("Epsilon1", typeof(double)));
            dtNormal.Columns.Add(new DataColumn("Epsilon0", typeof(double)));
            
            try
            {
                for (int i = 0; i < numberOfExperimentsToCreate; i++)
                {
                    //Random rand = new Random();

                    #region Values for eps and comp can be the same between agents
                    ////Get random starting values for the epsilon and competence:
                    //eps0 = Math.Round(rand.NextDouble(), 1);
                    //eps1 = Math.Round(rand.NextDouble(), 1);
                    //eps2 = Math.Round(rand.NextDouble(), 1);

                    ////Make sure eps are between 0.1 and 0.9
                    //CheckNumIsBetweenValidRange(ref eps0);
                    //CheckNumIsBetweenValidRange(ref eps1);
                    //CheckNumIsBetweenValidRange(ref eps2);

                    //competence0 = Math.Round(rand.NextDouble(), 1);
                    //competence1 = Math.Round(rand.NextDouble(), 1);
                    //competence2 = Math.Round(rand.NextDouble(), 1);

                    ////Make sure we do not have comp of 1 or 0
                    //CheckNumIsBetweenValidRange(ref competence0);
                    //CheckNumIsBetweenValidRange(ref competence1);
                    //CheckNumIsBetweenValidRange(ref competence2);
                    #endregion

                    #region Values for eps and comp are DIFFERENT between agents
                    //Get random starting values for the epsilon and competence:
                    eps0 = Math.Round(rand.NextDouble(), 1);
                    CheckNumIsBetweenValidRange(ref eps0);
                    do
                    {
                        eps1 = Math.Round(rand.NextDouble(), 1);
                        CheckNumIsBetweenValidRange(ref eps1);
                    } while (eps1 == eps0);

                    do
                    {
                        eps2 = Math.Round(rand.NextDouble(), 1);
                        CheckNumIsBetweenValidRange(ref eps2);
                    } while (eps2 == eps1 || eps2 == eps0);

                    competence0 = Math.Round(rand.NextDouble(), 1);
                    CheckNumIsBetweenValidRange(ref competence0);
                    do
                    {
                        competence1 = Math.Round(rand.NextDouble(), 1);
                        CheckNumIsBetweenValidRange(ref competence1);
                    } while (competence1 == competence0);
                    do
                    {
                        competence2 = Math.Round(rand.NextDouble(), 1);
                        CheckNumIsBetweenValidRange(ref competence2);
                    } while (competence2 == competence1 || competence2 == competence0);
                    #endregion

                    roundsPerGame = rand.Next(290) + 10;

                    #region add the data to the dataTable
                    for (int j = 0; j < numberOfGamesPerExperiment; j++)
                    {
                        //set new rows for the game
                        row1 = dtNormal.NewRow();

                        //enter game number
                        row1["Game_Number"] = i;

                        //enter number of rounds
                        row1["Rounds"] = roundsPerGame;

                        //save the epsilon value in the DataRows
                        row1["Epsilon0"] = eps0;
                        row1["Epsilon1"] = eps1;
                        row1["Epsilon2"] = eps2;

                        //save the competence value in the DataRows
                        row1["competence0"] = competence0;
                        row1["competence1"] = competence1;
                        row1["competence2"] = competence2;

                        //Add the dataRow to the datatable
                        dtNormal.Rows.Add(row1);
                    }
                    #endregion                   
                }
                //create file names and write to the files
                String stamp = DateTime.Now.ToString("yyyy.MM.dd-HH.mm.ss");
                WriteToCSV("data.csv", dtNormal);
                retVal = true;
            }
            catch (Exception ex)
            {
                outErrors = ex.ToString();
            }

            return retVal;
        }

        protected void CheckNumIsBetweenValidRange(ref double comp)
        {
            while (comp == 0 || comp == 1)
            {
                comp = Math.Round(rand.NextDouble(), 1);
            }
        }

        /// <summary>
        /// A function to write the XML file as a CSV file ready for opening in excel
        /// </summary>
        /// <param name="fileName">Name of the file</param>
        /// <param name="dt">The data Table to print</param>
        private void WriteToCSV(String fileName, DataTable dt)
        {
            //set an output writer
            System.IO.TextWriter writer = new System.IO.StreamWriter(fileName);

            //print columns name
            for (int i = 0; i < dt.Columns.Count; ++i)
                writer.Write(dt.Columns[i].ToString() + ",");

            writer.WriteLine();

            //for each row...
            for (int i = 0; i < dt.Rows.Count; ++i)
            {
                DataRow row = dt.Rows[i];
                //for each cell in the row...
                for (int j = 0; j < dt.Columns.Count; ++j)
                    writer.Write(row[j].ToString() + ",");
                writer.WriteLine();
            }

            writer.Close();
        }

        /// <summary>
        /// Build the datatable from a CSV file
        /// </summary>
        /// <param name="inFilePath">The path on the hard drive</param>
        /// <param name="outErrors">Exception</param>
        /// <returns>DataTable</returns>
        private DataTable BuildDataTable(string inFilePath, out int outNumOfGames, out string outErrors)
        {
            DataTable myTable = new DataTable("MyTable");
            int i;
            DataRow myRow;
            string[] fieldValues;
            StreamReader myReader = new StreamReader(inFilePath);
            char splitChars = ',';
            outErrors = string.Empty;
            outNumOfGames = 0;

            try
            {
                //Open file and read first line to determine how many fields there are.
                fieldValues = myReader.ReadLine().Split(splitChars);

                //Create data columns accordingly
                for (i = 0; i < fieldValues.Length; i++)
                {
                    myTable.Columns.Add(new DataColumn(fieldValues[i]));
                }

                //Adding the first line of data to data table (which is the column name, can be SKIPPED!!!)
                myRow = myTable.NewRow();
                for (i = 0; i < fieldValues.Length; i++)
                {
                    myRow[i] = fieldValues[i].ToString();
                }
                myTable.Rows.Add(myRow);

                //Now reading the rest of the data to data table
                while (myReader.Peek() != -1)
                {
                    fieldValues = myReader.ReadLine().Split(splitChars);
                    myRow = myTable.NewRow();

                    for (i = 0; i < fieldValues.Length; i++)
                    {
                        myRow[i] = fieldValues[i].ToString();
                    }
                    myTable.Rows.Add(myRow);
                    outNumOfGames++;
                }
            }
            catch (Exception ex)
            {
                #region Test if there is a difference between ex.message to ex.toString()
                //Test if there is a difference between ex.message to ex.toString()... :
                string tempErr = ex.ToString();
                #endregion

                outErrors = ex.Message;
                return new DataTable("Empty");
            }
            finally
            {
                myReader.Close();
            }

            return myTable;
        }

        private void btnCreateNewExp_Click(object sender, EventArgs e)
        {
            string errors = string.Empty;
            CreateExperiment(string.Empty, out errors);
        }

        private void btnCreateNewExpFromNothing_Click(object sender, EventArgs e)
        {
            string errors = string.Empty;
            ExperimentGenerator(out errors);
        }

        #region General Result Analyzer

        private void btnAnalyzeGeneralResults_Click(object sender, EventArgs e)
        {
            string dirPath = @"C:\temp5\";
            string errors = string.Empty;
            
            int numOfGames;
            //List<DataTable> dtArray = new List<DataTable>();
            DirectoryInfo dir = new DirectoryInfo(dirPath);
            FileInfo[] csvFiles = dir.GetFiles("*.csv");
            DataRow row1;

            dtNormal = new DataTable("ResultAnalyze");
            DataColumn cln = new DataColumn("StudDetails", typeof(string));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Competence0", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Competence1", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Competence2", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("eps0", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("eps1", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("eps2", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("avgUtilityOfTheGame", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Player0NumOfTurnsPlayed", typeof(int));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Player1NumOfTurnsPlayed", typeof(int));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Player2NumOfTurnsPlayed", typeof(int));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Player0AccumUtility", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Player1AccumUtility", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Player2AccumUtility", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Player0AvgUtility", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Player1AvgUtility", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Player2AvgUtility", typeof(double));
            dtNormal.Columns.Add(cln);
            cln = new DataColumn("Rounds", typeof(double));
            dtNormal.Columns.Add(cln);

            foreach (FileInfo fi in csvFiles)
            {
                string filePath = string.Concat(dirPath, @"\", fi.Name);//@dirPath + "\" + fi.Name;
                DataTable dt = BuildResultAnalyzeDataTable(filePath, out numOfGames, out errors);
                if (dt != null)
                {
                    //expRun(numOfGames, dt, fi.Name.Substring(0, (fi.Name.Length - 4)));
                    
                    row1 = dtNormal.NewRow();
                    AnalyzeDataTable(dt, numOfGames, row1);
                    row1["StudDetails"] = fi.Name.Substring(0, (fi.Name.Length - 4));
                    dtNormal.Rows.Add(row1);
                }                
            }
            String stamp = DateTime.Now.ToString("yyyy.MM.dd-HH.mm.ss");
            WriteToCSV("Results_" + stamp + ".csv", dtNormal); 
        }

        private void AnalyzeDataTable(DataTable dtFromCSV, int inNumberOfGames, DataRow inRow)
        {
            int rounds = 0;
            double competence0 = 0;
            double competence1 = 0;
            double competence2 = 0;
            double eps0 = 0;
            double eps1 = 0;
            double eps2 = 0;
            double avgUtilityOfTheGame = 0;
            double Player0NumOfTurnsPlayed = 0;
            double Player1NumOfTurnsPlayed = 0;
            double Player2NumOfTurnsPlayed = 0;
            double Player0AccumUtility = 0;
            double Player1AccumUtility = 0;
            double Player2AccumUtility = 0;
            double Player0AvgUtility = 0;
            double Player1AvgUtility = 0;
            double Player2AvgUtility = 0;
            
            for (int i = 0; i < inNumberOfGames; ++i)
            {
                eps0 += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[4].ToString());
                eps1 += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[5].ToString());
                eps2 += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[6].ToString());

                competence0 += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[1].ToString());
                competence1 += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[2].ToString());
                competence2 += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[3].ToString());

                //Get number of rounds to run the experiment
                rounds += int.Parse(dtFromCSV.Rows[i + 1].ItemArray[17].ToString());
                      
                avgUtilityOfTheGame += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[7].ToString());
                Player0NumOfTurnsPlayed += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[8].ToString());
                Player1NumOfTurnsPlayed += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[9].ToString());
                Player2NumOfTurnsPlayed += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[10].ToString());
                Player0AccumUtility += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[11].ToString());
                Player1AccumUtility += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[12].ToString());
                Player2AccumUtility += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[13].ToString());
                Player0AvgUtility += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[14].ToString());
                Player1AvgUtility += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[15].ToString());
                Player2AvgUtility += double.Parse(dtFromCSV.Rows[i + 1].ItemArray[16].ToString());                
            }
            
            inRow["Competence0"] = competence0 / inNumberOfGames;
            inRow["Competence1"] = competence1 / inNumberOfGames;
            inRow["Competence2"] = competence2 / inNumberOfGames;
            inRow["eps0"] = eps0 / inNumberOfGames;
            inRow["eps1"] = eps1 / inNumberOfGames;
            inRow["eps2"] = eps2 / inNumberOfGames;
            inRow["avgUtilityOfTheGame"] = avgUtilityOfTheGame / inNumberOfGames;
            inRow["Player0NumOfTurnsPlayed"] = Player0NumOfTurnsPlayed / inNumberOfGames;
            inRow["Player1NumOfTurnsPlayed"] = Player1NumOfTurnsPlayed / inNumberOfGames;
            inRow["Player2NumOfTurnsPlayed"] = Player2NumOfTurnsPlayed / inNumberOfGames;
            inRow["Player0AccumUtility"] = Player0AccumUtility / inNumberOfGames;
            inRow["Player1AccumUtility"] = Player1AccumUtility / inNumberOfGames;
            inRow["Player2AccumUtility"] = Player2AccumUtility / inNumberOfGames;
            inRow["Player0AvgUtility"] = Player0AvgUtility / inNumberOfGames;
            inRow["Player1AvgUtility"] = Player1AvgUtility / inNumberOfGames;
            inRow["Player2AvgUtility"] = Player2AvgUtility / inNumberOfGames;
            inRow["Rounds"] = rounds / inNumberOfGames;
        }

        private DataTable BuildResultAnalyzeDataTable(string inFilePath, out int outNumOfGames, out string outErrors)
        {
            DataTable myTable = new DataTable("MyTable");
            int i;
            DataRow myRow;
            string[] fieldValues;
            StreamReader myReader = new StreamReader(inFilePath);
            char splitChars = ',';
            outErrors = string.Empty;
            outNumOfGames = 0;

            try
            {
                //Open file and read first line to determine how many fields there are.
                fieldValues = myReader.ReadLine().Split(splitChars);

                //Create data columns accordingly
                for (i = 0; i < fieldValues.Length; i++)
                {
                    myTable.Columns.Add(new DataColumn(fieldValues[i]));
                }

                //Adding the first line of data to data table (which is the column name, can be SKIPPED!!!)
                myRow = myTable.NewRow();
                for (i = 0; i < fieldValues.Length; i++)
                {
                    myRow[i] = fieldValues[i].ToString();
                }
                myTable.Rows.Add(myRow);

                //Now reading the rest of the data to data table
                while (myReader.Peek() != -1)
                {
                    fieldValues = myReader.ReadLine().Split(splitChars);
                    myRow = myTable.NewRow();

                    for (i = 0; i < fieldValues.Length; i++)
                    {
                        myRow[i] = fieldValues[i].ToString();
                    }
                    myTable.Rows.Add(myRow);
                    outNumOfGames++;
                }
            }
            catch (Exception ex)
            {
                #region Test if there is a difference between ex.message to ex.toString()
                //Test if there is a difference between ex.message to ex.toString()... :
                string tempErr = ex.ToString();
                #endregion

                outErrors = ex.Message;
                return new DataTable("Empty");
            }
            finally
            {
                myReader.Close();
            }

            return myTable;
        }

        #endregion

       
        #region Students specific csv Analyzer

        private void btnAnalyzeStudentsCSV_Click(object sender, EventArgs e)
        {
            string dirPath = @"C:\temp4\";
            string errors = string.Empty;
            DataTable dt;
            int numOfGames;
            //List<DataTable> dtArray = new List<DataTable>();
            DirectoryInfo dir = new DirectoryInfo(dirPath);
            DirectoryInfo[] allDir =  dir.GetDirectories();
            foreach (DirectoryInfo dirInfo in allDir)
            {
                string fileName = dirInfo.Name;
                FileInfo[] csvFiles = dirInfo.GetFiles("*.csv");
                DataRow row1;

                dtNormal = new DataTable("ResultAnalyze");
                DataColumn cln = new DataColumn("StudDetails", typeof(string));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Competence0", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Competence1", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Competence2", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("eps0", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("eps1", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("eps2", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("avgUtilityOfTheGame", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Player0NumOfTurnsPlayed", typeof(int));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Player1NumOfTurnsPlayed", typeof(int));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Player2NumOfTurnsPlayed", typeof(int));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Player0AccumUtility", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Player1AccumUtility", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Player2AccumUtility", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Player0AvgUtility", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Player1AvgUtility", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Player2AvgUtility", typeof(double));
                dtNormal.Columns.Add(cln);
                cln = new DataColumn("Rounds", typeof(double));
                dtNormal.Columns.Add(cln);

                foreach (FileInfo fi in csvFiles)
                {
                    string filePath = string.Concat(dirInfo.FullName, @"\", fi.Name);//@dirPath + "\" + fi.Name;
                    dt = BuildResultAnalyzeDataTable(filePath, out numOfGames, out errors);
                    if (dt != null)
                    {
                        //expRun(numOfGames, dt, fi.Name.Substring(0, (fi.Name.Length - 4)));

                        row1 = dtNormal.NewRow();
                        AnalyzeDataTable(dt, numOfGames, row1);
                        string[] fullName = fi.Name.Substring(0, (fi.Name.Length - 4)).Split('_');
                        string studentAgent = string.Join("_", fullName, 4, 3);
                        //string studentAgent = string.Join("_", fullName, 1, 3); // if want to sum on temp6 everyones agents on one students problems
                        row1["StudDetails"] = studentAgent;
                        dtNormal.Rows.Add(row1);
                    }                    
                }
                String stamp = DateTime.Now.ToString("yyyy.MM.dd-HH.mm.ss");
                WriteToCSV(fileName + "_" + stamp + ".csv", dtNormal);
            }
        }


        #endregion
    }
}
